package cn.ydxiaoshuai.workrecord;

import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apkinfo.api.util.AXmlResourceParser;

import java.io.File;
import java.io.IOException;
import java.util.Enumeration;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

/**
 * @author 小帅丶
 * @className AnalyticApkSample
 * @Description 读取安卓APK信息
 * 如果POM引入下载失败，请手动下载JAR安装到本地maven仓库
 * mvn install:install-file -Dfile=JAR本地目录 -DgroupId=org.apkinfo -DartifactId=AXmlResourceParser -Dversion=1.0 -Dpackaging=jar
 * @Date 2021-07-23-16:22
 **/
@Slf4j
public class AnalyticApkSample {
    public static void main(String[] args) {
        try {
            ApkInfo apkInfo = unZip("C:\\Users\\Administrator\\Downloads\\link.apk");
            System.out.println(apkInfo.toString());
        } catch (Exception e) {
            log.info("读取错误--->{}",e.getMessage());
        }
    }
    @Data
    public static class ApkInfo{
        //版本号
        private String versionName;
        //包名
        private String packageName;
        //版本号 不带·
        private String versionCode;
        @Override
        public String toString() {
            return "ApkInfo{" +
                    "versionName='" + versionName + '\'' +
                    ", packageName='" + packageName + '\'' +
                    ", versionCode='" + versionCode + '\'' +
                    '}';
        }
    }

    public static ApkInfo unZip(String apkUrl) {
        ApkInfo apkInfo = new ApkInfo();
        byte[] b = new byte['E'];
        try {
            ZipFile zipFile = new ZipFile(new File(apkUrl));
            Enumeration enumeration = zipFile.entries();
            ZipEntry zipEntry = null;
            while (enumeration.hasMoreElements()) {
                zipEntry = (ZipEntry) enumeration.nextElement();
                if ((!zipEntry.isDirectory()) &&
                        ("AndroidManifest.xml".equals(zipEntry.getName()))) {
                    try {
                        AXmlResourceParser parser = new AXmlResourceParser();
                        parser.open(zipFile.getInputStream(zipEntry));
                        //等同于while(true) 指令少，不占用寄存器，而且没有判断跳转
                        for (; ;) {
                            int type = parser.next();
                            if (type == 1) {
                                break;
                            }
                            switch (type) {
                                case 2:
                                    for (int i = 0; i != parser.getAttributeCount(); i++) {
                                        if ("versionName".equals(parser.getAttributeName(i))) {
                                            apkInfo.setVersionName(getAttributeValue(parser, i));
                                        } else if ("package".equals(parser.getAttributeName(i))) {
                                            apkInfo.setPackageName(getAttributeValue(parser, i));
                                        } else if ("versionCode".equals(parser.getAttributeName(i))) {
                                            apkInfo.setVersionCode(getAttributeValue(parser, i));
                                        }
                                    }
                            }
                        }
                    } catch (Exception e) {
                        log.info("解析错误--->{}",e.getMessage());
                    }
                }
            }
        } catch (IOException e) {
            log.info("读取APK错误--->{}",e.getMessage());
        }
        return apkInfo;
    }

    private static String getAttributeValue(AXmlResourceParser parser, int index) {
        int type = parser.getAttributeValueType(index);
        int data = parser.getAttributeValueData(index);
        if (type == 3) {
            return parser.getAttributeValue(index);
        }
        if (type == 2) {
            return String.format("?%s%08X", new Object[]{getPackage(data), Integer.valueOf(data)});
        }
        if (type == 1) {
            return String.format("@%s%08X", new Object[]{getPackage(data), Integer.valueOf(data)});
        }
        if (type == 4) {
            return String.valueOf(Float.intBitsToFloat(data));
        }
        if (type == 17) {
            return String.format("0x%08X", new Object[]{Integer.valueOf(data)});
        }
        if (type == 18) {
            return data != 0 ? "true" : "false";
        }
        if (type == 5) {
            return Float.toString(complexToFloat(data)) + DIMENSION_UNITS[(data & 0xF)];
        }
        if (type == 6) {
            return Float.toString(complexToFloat(data)) + FRACTION_UNITS[(data & 0xF)];
        }
        if ((type >= 28) && (type <= 31)) {
            return String.format("#%08X", new Object[]{Integer.valueOf(data)});
        }
        if ((type >= 16) && (type <= 31)) {
            return String.valueOf(data);
        }
        return String.format("<0x%X, type 0x%02X>", new Object[]{Integer.valueOf(data), Integer.valueOf(type)});
    }

    private static String getPackage(int id) {
        if (id >>> 24 == 1) {
            return "android:";
        }
        return "";
    }

    public static float complexToFloat(int complex) {
        return (complex & 0xFF00) * RADIX_MULTS[(complex >> 4 & 0x3)];
    }

    private static final float[] RADIX_MULTS = {0.00390625F, 3.051758E-5F, 1.192093E-7F, 4.656613E-10F};
    private static final String[] DIMENSION_UNITS = {"px", "dip", "sp", "pt", "in", "mm", "", ""};
    private static final String[] FRACTION_UNITS = {"%", "%p", "", "", "", "", "", ""};
}
